from flask.scaffold import T_route
from flask_siwadoc import SiwaDoc

from functools import wraps
from typing import Optional, Type, Callable, Any

from flask import Blueprint
from pydantic import BaseModel


class MySiwaDoc(SiwaDoc):
    def blueprint(self, *args, **kwargs):
        return SiwaBlueprint(self, *args, **kwargs)


class SiwaBlueprint(Blueprint):
    siwa: SiwaDoc
    tags = []
    group = None

    def __init__(self, siwa: SiwaDoc, *args, **kwargs):
        self.siwa = siwa
        if 'tags' in kwargs:
            self.tags = kwargs.pop('tags')
        if 'group' in kwargs:
            self.group = kwargs.pop('group')

        super().__init__(*args, **kwargs)

    def route(self,
              rule,
              *,
              query: Optional[Type[BaseModel]] = None,
              header: Optional[Type[BaseModel]] = None,
              cookie: Optional[Type[BaseModel]] = None,
              body: Optional[Type[BaseModel]] = None,
              form: Optional[Type[BaseModel]] = None,
              files=None,
              resp=None,
              x=[],
              tags=[],
              group=None,
              summary=None,
              description=None,
              ignore=False,
              **options: Any) -> Callable[[T_route], T_route]:

        # 忽略不使用 siwadoc 的接口
        if ignore:
            return super().route(rule, **options)

        def decorator(func) -> T_route:
            view_func = self.siwa.doc(query,
                                      header,
                                      cookie,
                                      body,
                                      form,
                                      files,
                                      resp,
                                      x,
                                      tags or self.tags,
                                      group or self.group,
                                      summary,
                                      description)(func)
            view = self.__blueprint_route(view_func, rule, **options)

            @wraps
            def inner(*args, **kwargs):
                return view(*args, **kwargs)

            return inner

        return decorator

    def __blueprint_route(self, view_func, rule, **options):
        return super().route(rule, **options)(view_func)


siwa = MySiwaDoc()